/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.web.npmpackagepatch;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.inspur.edp.web.npmpackagepatch.packagejson.PackageJsonDependencyInfo;
import com.inspur.edp.web.npmpackagepatch.packagejson.PackageJsonInfo;
import com.inspur.edp.web.npmpackagepatch.packagejson.SerializedPackageJson;

import java.util.*;

public class SerializePackageJson {
    private final ObjectMapper defaultObjectMapper;

    private SerializePackageJson() {
        defaultObjectMapper = this.createDefaultObjectMapper();
    }

    private static volatile SerializePackageJson serializeUtilityInstance = null;

    public static SerializePackageJson getInstance() {
        if (serializeUtilityInstance == null) {
            synchronized (SerializePackageJson.class) {
                if (serializeUtilityInstance == null) {
                    serializeUtilityInstance = new SerializePackageJson();
                }
            }
        }

        return serializeUtilityInstance;
    }

    private ObjectMapper createDefaultObjectMapper() {
        ObjectMapper mapper = new ObjectMapper();
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        mapper.setPropertyNamingStrategy(new MyPropertyNamingStrategy());
        PropertyNamingStrategy currentNameStrategy = mapper.getPropertyNamingStrategy();
        mapper.setPropertyNamingStrategy(currentNameStrategy);
        return mapper;
    }


    /**
     * Deserialize string to an object.
     * 将一个对象字符串反序列化成对象
     *
     * @param contentString the content string
     * @return the t
     * @description Json反序列化
     */
    public PackageJsonInfo deserialize(String contentString) {
        try {
            return packageJsonInfoGenerate(contentString);
        } catch (Exception ex) {
            throw new RuntimeException(ex.getMessage(), ex);
        }
    }

    public PackageJsonInfo packageJsonInfoGenerate(String serverPackageJsonContent) {
        PackageJsonInfo packageJsonInfo = new PackageJsonInfo();
        try {
            JsonNode jsonNode = this.defaultObjectMapper.readTree(serverPackageJsonContent);
            String packageJsonName = jsonNode.get("name").asText();
            packageJsonInfo.setName(packageJsonName);

            String packageJsonVersion = jsonNode.get("version").asText();
            packageJsonInfo.setVersion(packageJsonVersion);

            String packageJsonDescription = jsonNode.get("description").asText();
            packageJsonInfo.setDescription(packageJsonDescription);

            String packageJsonAuthor = jsonNode.get("author").textValue();
            packageJsonInfo.setAuthor(packageJsonAuthor);

            String packageJsonLicense = jsonNode.get("license").asText();
            packageJsonInfo.setLicense(packageJsonLicense);

            ObjectNode dependenciesObjNode = (ObjectNode) jsonNode.get("dependencies");
            ObjectNode devDependenciesObjNode = (ObjectNode) jsonNode.get("devDependencies");

            if (dependenciesObjNode != null) {
                Iterator<Map.Entry<String, JsonNode>> iterator = dependenciesObjNode.fields();
                while (iterator.hasNext()) {
                    Map.Entry<String, JsonNode> field = iterator.next();
                    if (field != null && field.getKey() != null && field.getValue() != null && field.getValue().textValue() != null) {
                        packageJsonInfo.getDependencies().add(new PackageJsonDependencyInfo(field.getKey(), field.getValue().textValue()));
                    }
                }
            }

            if (devDependenciesObjNode != null) {
                Iterator<Map.Entry<String, JsonNode>> iterator = devDependenciesObjNode.fields();
                while (iterator.hasNext()) {
                    Map.Entry<String, JsonNode> field = iterator.next();
                    if (field != null && field.getKey() != null && field.getValue() != null && field.getValue().textValue() != null) {
                        packageJsonInfo.getDevDependencies().add(new PackageJsonDependencyInfo(field.getKey(), field.getValue().textValue()));
                    }
                }
            }
        } catch (Exception e) {
            System.out.println("Npm 在线安装出现异常：" + e.getMessage() + Arrays.toString(e.getStackTrace()));
            throw new RuntimeException(e.getMessage(), e);
        }


        return packageJsonInfo;
    }

    /**
     * Serialize an object to string.
     * 保持属性名称一致
     *
     * @param entity the entity
     * @return the string instance
     * @description Json序列化
     */
    public String serialize(PackageJsonInfo entity) {
        SerializedPackageJson serializedPackageJson = convertToSerializedPackageJson(entity);

        String result = serialize(this.defaultObjectMapper, serializedPackageJson, true);
        return result;
    }

    private SerializedPackageJson convertToSerializedPackageJson(PackageJsonInfo entity) {
        SerializedPackageJson serializedPackageJson = new SerializedPackageJson();
        serializedPackageJson.setName(entity.getName());

        LinkedHashMap<String, String> dependencyMap = new LinkedHashMap<>();
        entity.getDependencies().forEach(t -> dependencyMap.put(t.getKey(), t.getValue()));
        serializedPackageJson.setDependencies(dependencyMap);

        serializedPackageJson.setAuthor(entity.getAuthor());
        serializedPackageJson.setDescription(entity.getDescription());
        serializedPackageJson.setKeywords(entity.getKeywords());
        serializedPackageJson.setLicense(entity.getLicense());
        serializedPackageJson.setVersion(entity.getVersion());

        LinkedHashMap<String, String> devDependencyMap = new LinkedHashMap<>();
        entity.getDevDependencies().forEach(t -> devDependencyMap.put(t.getKey(), t.getValue()));
        serializedPackageJson.setDevDependencies(devDependencyMap);
        return serializedPackageJson;
    }


    /**
     * Serialize an object to string.
     *
     * @param objectMapper the objectMapper
     * @param entity       the entity
     * @return the string instance
     * @description Json序列化
     */
    public String serialize(ObjectMapper objectMapper, Object entity, boolean usePretty) {
        if (entity == null) {
            return null;
        }

        String serializeStr = null;

        try {
            if (!usePretty) {
                serializeStr = objectMapper.writeValueAsString(entity);
            } else {
                serializeStr = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(entity);
            }

            return serializeStr;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }


    // endregion

    // region 自定义配置

}



